package com.fly.core.utils;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class InvalidIPv4Generator
{
    private static final Random random = new Random();
    
    public static Stream<String> invalidIPv4Provider()
    {
        return Stream.of("000.000.000.000", // leading 0
            "00.00.00.00", // leading 0
            "1.2.3.04", // leading 0
            "1.02.03.4", // leading 0
            "1.2", // 1 dot
            "1.2.3", // 2 dots
            "1.2.3.4.5", // 4 dots
            "192.168.1.1.1", // 4 dots
            "256.1.1.1", // 256
            "1.256.1.1", // 256
            "1.1.256.1", // 256
            "1.1.1.256", // 256
            "-100.1.1.1", // -100
            "1.-100.1.1", // -100
            "1.1.-100.1", // -100
            "1.1.1.-100", // -100
            "1...1", // empty between .
            "1..1", // empty between .
            "1.1.1.1.", // last .
            ""); // empty
    }
    
    /**
     * 创建ip
     * 
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static String buildIp()
    {
        List<String> nums = random.ints(4, -10, 300).mapToObj(Objects::toString).collect(Collectors.toList());
        String ip = StringUtils.join(nums, ".");
        log.info("IP4地址: {}", ip);
        
        // 随机插入.字母(a-z)数字(0-9)
        String insert;
        switch (RandomUtils.nextInt(0, 5))
        {
            case 0:
                insert = ".";
                break;
            case 1:
                insert = RandomStringUtils.randomAlphabetic(1);
                break;
            case 2:
                insert = RandomStringUtils.randomNumeric(1);
                break;
            default:
                return ip;
        }
        int index = RandomUtils.nextInt(0, ip.length());
        return StringUtils.substring(ip, 0, index) + insert + StringUtils.substring(ip, index);
    }
    
    public static String generateInvalidIPv4()
    {
        // 0~5，代表不同的非法模式
        switch (random.nextInt(6))
        {
            case 0:
                return generateInvalidPartValue(); // 某个部分超出 0-255
            case 1:
                return generateInvalidLeadingZero(); // 某个部分有前导零
            case 2:
                return generateInvalidPartCount(); // 部分数量错误
            case 3:
                return generateInvalidChar(); // 包含非数字字符
            case 4:
                return generateConsecutiveDots(); // 连续点
            case 5:
                return generateInvalidStartOrEnd(); // 以点开头或结尾
            default:
                return "192.168.1.1"; // 默认合法地址（不会发生）
        }
    }
    
    // 生成某个部分超出 0-255 的非法地址
    private static String generateInvalidPartValue()
    {
        int partIndex = random.nextInt(4);
        StringBuilder ip = new StringBuilder();
        for (int i = 0; i < 4; i++)
        {
            if (i == partIndex)
            {
                ip.append(random.nextInt(745) + 255); // 256~999
            }
            else
            {
                ip.append(random.nextInt(256));
            }
            if (i < 3)
                ip.append(".");
        }
        return ip.toString();
    }
    
    // 生成某个部分带有前导零的非法地址
    private static String generateInvalidLeadingZero()
    {
        int partIndex = random.nextInt(4);
        StringBuilder ip = new StringBuilder();
        for (int i = 0; i < 4; i++)
        {
            if (i == partIndex)
            {
                int value = random.nextInt(256); // 1~255
                ip.append("0").append(value); // 添加前导零
            }
            else
            {
                ip.append(random.nextInt(256));
            }
            if (i < 3)
                ip.append(".");
        }
        return ip.toString();
    }
    
    // 生成部分数量错误的非法地址
    private static String generateInvalidPartCount()
    {
        int partCount = random.nextBoolean() ? 3 : 5;
        List<String> parts = new ArrayList<>();
        for (int i = 0; i < partCount; i++)
        {
            parts.add(String.valueOf(random.nextInt(256)));
        }
        return String.join(".", parts);
    }
    
    // 生成包含非数字字符的非法地址
    private static String generateInvalidChar()
    {
        int partIndex = random.nextInt(4);
        List<String> parts = new ArrayList<>();
        for (int i = 0; i < 4; i++)
        {
            if (i == partIndex)
            {
                parts.add(generateInvalidCharPart());
            }
            else
            {
                parts.add(String.valueOf(random.nextInt(256)));
            }
        }
        return String.join(".", parts);
    }
    
    private static String generateInvalidCharPart()
    {
        String[] invalidChars = {"a", "b", "x", "y", "z", "A", "B", "X", "Y", "Z"};
        String base = String.valueOf(random.nextInt(256));
        int index = random.nextInt(base.length());
        return base.substring(0, index) + invalidChars[random.nextInt(invalidChars.length)] + base.substring(index);
    }
    
    // 生成包含连续点的非法地址
    private static String generateConsecutiveDots()
    {
        List<String> parts = new ArrayList<>();
        for (int i = 0; i < 4; i++)
        {
            parts.add(String.valueOf(random.nextInt(256)));
        }
        int insertIndex = random.nextInt(3);
        parts.set(insertIndex, parts.get(insertIndex) + ".");
        return String.join(".", parts);
    }
    
    // 生成以点开头或结尾的非法地址
    private static String generateInvalidStartOrEnd()
    {
        String validIP = generateValidIPv4();
        if (random.nextBoolean())
        {
            return "." + validIP;
        }
        else
        {
            return validIP + ".";
        }
    }
    
    // 生成合法的 IPv4 地址（辅助方法）
    private static String generateValidIPv4()
    {
        List<String> parts = new ArrayList<>();
        for (int i = 0; i < 4; i++)
        {
            parts.add(String.valueOf(random.nextInt(256)));
        }
        return String.join(".", parts);
    }
}